#include "EPollPoller.h"
#include "Logger.h"
#include "Channel.h"

#include <errno.h>
#include <unistd.h>
#include <strings.h>

/// @brief channel的状态
const int kNew = -1; // 未添加到poller中
const int kAdd = 1;  // 已添加到poller中
const int kDel = 2;  // 已从poller中删除

EPollPoller::EPollPoller(EventLoop *loop)
    : Poller(loop), epollfd_(epoll_create1(EPOLL_CLOEXEC)) // 子线程拷贝替换程序时关闭这个文件描述符
      ,
      events_(kInitEventListSize)
{
    if (epollfd_ < 0)
    {
        LOG_FATAL("epoll_create error:%d\n", errno);
    }
}
EPollPoller::~EPollPoller()
{
    if (epollfd_ >= 0)
    {
        close(epollfd_);
    }
}
/**
 * @brief 获取就绪事件并写入events_
 *
 * @param timeoutMs
 * @param activeChannels
 * @return Timestamp
 */
Timestamp EPollPoller::poll(int timeoutMs, ChannelList *activeChannels)
{
    LOG_INFO("func=%s; fd cnt:%lu\n", __FUNCTION__, channels_.size());

    int numEvents = epoll_wait(epollfd_, &*events_.begin(), static_cast<int>(events_.size()), timeoutMs);
    int saveError = errno;           // 保存错误码，避免在多线程中丢失错误信息
    Timestamp now(Timestamp::now()); // 保存时间戳
    if (numEvents > 0)               // 有事件就绪
    {
        LOG_INFO("%d events happened\n", numEvents);
        fillActiveChannels(numEvents, activeChannels);
        if (numEvents == events_.size()) // 扩容
        {
            events_.resize(events_.size() * 2);
        }
    }
    else if (numEvents == 0) // timeout
    {
        LOG_DEBUG("%s timeout!\n", __FUNCTION__);
    }
    else // error
    {
        if (saveError != EINTR)
        {
            errno = saveError;
            LOG_ERROR("EPollPoller::poll() error:%d\n", errno);
        }
    }
    return now;
}
/**
 * @brief 更新channel
 *
 * @param channel
 */
void EPollPoller::updateChannel(Channel *channel)
{
    const int index = channel->index();
    LOG_INFO("func=%s fd=%d events=%d index=%d\n", __FUNCTION__, channel->fd(), channel->events(), index);

    if (index == kNew || index == kDel)
    {
        if (index == kNew)
        {
            int fd = channel->fd();
            channels_[fd] = channel; // 添加到channels中
        }
        update(EPOLL_CTL_ADD, channel); // 添加到epoll中
        channel->set_index(kAdd);       // 状态更新
    }
    else // 已经在poller中注册过了，需要进行修改关注的事件
    {
        int fd = channel->fd();
        if (channel->isNoneEvent()) // 移除
        {
            update(EPOLL_CTL_DEL, channel);
            channel->set_index(kDel);
        }
        else // 修改
        {
            update(EPOLL_CTL_MOD, channel);
        }
    }
}
/**
 * @brief 将channel中poller中移除
 *
 * @param channel
 */
void EPollPoller::removeChannel(Channel *channel)
{
    int fd = channel->fd();
    channels_.erase(fd); // 从channels中移除

    LOG_INFO("func=%s fd=%d\n", __FUNCTION__, fd);

    int index = channel->index();
    if (index == kAdd) // 从poller中移除
    {
        update(EPOLL_CTL_DEL, channel);
    }
    channel->set_index(kNew);
}
/**
 * @brief 将就绪的event事件封装成Channel
 *
 * @param numEvents
 * @param activeChannels
 */
void EPollPoller::fillActiveChannels(int numEvents, ChannelList *activeChannels)
{
    for (int i = 0; i < numEvents; i++)
    {
        Channel *channel = static_cast<Channel *>(events_[i].data.ptr);
        channel->set_revents(events_[i].events); // 填入就绪的事件
        activeChannels->push_back(channel);      // 加入激活Channels队列
    }
}
/**
 * @brief 控制epoll结构中关注的事件
 *
 * @param operation
 * @param channel
 */
void EPollPoller::update(int operation, Channel *channel)
{
    epoll_event event;
    bzero(&event, sizeof(event));

    int fd = channel->fd();
    // 填写event信息-将channel转变成event
    event.data.fd = fd;
    event.data.ptr = channel;
    event.events = channel->events();

    if (epoll_ctl(epollfd_, operation, fd, &event) < 0)
    {
        if (operation == EPOLL_CTL_DEL) // 删除失败
        {
            LOG_ERROR("epoll_ctl del error:%d\n", errno);
        }
        else // 添加/修改失败，无法进行下去
        {
            LOG_FATAL("epoll_ctl add/mod error:%d\n", errno);
        }
    }
}